using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.IO;
using Ltf.Remoting.TeamFoundation;
using Ltf.Remoting.Settings;
using System.Runtime.InteropServices;

namespace Ltf.Remoting.TFAccess
{
	public class LocalTFDifRepository : IDifRepository
	{
		[DllImport("imagehlp.dll")]
		public static extern int MapFileAndCheckSumA(string fileName, ref int headerSum, ref int checkSum);

		private VersionControlServer vcServer;
		private string tempPath;

		Dictionary<string, Item> itemCache = null;
		Dictionary<string, ExtendedItem> extItemCache = null;

		public void PrepCache(string fsPath)
		{
			Workspace ws = vcServer.GetWorkspace(fsPath);
			itemCache = new Dictionary<string, Item>();
			extItemCache = new Dictionary<string, ExtendedItem>();
			VersionSpec vs = VersionSpec.Latest;
			if (version > 0)
				vs = new ChangesetVersionSpec(version);
			ItemSet items = vcServer.GetItems(ws.GetServerItemForLocalItem(fsPath), vs, RecursionType.Full);
			foreach (Item item in items.Items)
			{
				itemCache.Add(item.ServerItem, item);
			}
			ItemSpec itemSpec = new ItemSpec(fsPath, RecursionType.Full);
			ExtendedItem[] extItems = ws.GetExtendedItems(new ItemSpec[] { itemSpec }, DeletedState.NonDeleted, ItemType.Any)[0];
			foreach (ExtendedItem extItem in extItems)
			{
				if (extItem.LocalItem != null)
					extItemCache.Add(extItem.LocalItem, extItem);
			}
		}



		public LocalTFDifRepository(VersionControlServer vcServer, string tempPath)
		{
			this.vcServer = vcServer;
			this.tempPath = tempPath;
		}

		private int version = 0;

		public int Version
		{
			get { return version; }
			set { version = value; }
		}

		#region IDifRepository Members

		public bool FolderExists(string path)
		{
			return (Directory.Exists(path) && Directory.Exists(ServerConnections.GetConnectionForPath(path).GetMetaFolder(path)));
		}

		public bool FileExists(string path)
		{
			return (File.Exists(path)
				&& Directory.Exists(ServerConnections.GetConnectionForPath(path).GetMetaFolder(path)));
		}

		public bool FileOrFolderExists(string path)
		{
			return FolderExists(path) || FileExists(path);
		}

		public IEnumerable<string> GetFolderItems(string path, DifItemType itemType)
		{
			if (FolderExists(path))
			{
				if (version == 0)
				{
					if (!extItemCache.ContainsKey(path))
					{
						Workspace ws = vcServer.GetWorkspace(path);
						if (ws != null)
						{
							ItemSpec[] itemSpecs = new ItemSpec[] { new ItemSpec(path, RecursionType.OneLevel) };
							ExtendedItem[] extItems = ws.GetExtendedItems(itemSpecs, DeletedState.Any, ItemType.File)[0];
							foreach (ExtendedItem extItem in extItems)
							{
								if (extItem.DeletionId == 0 && itemType == DifItemType.Any
									|| (itemType == DifItemType.File && extItem.ItemType == ItemType.File)
									|| (itemType == DifItemType.Folder && extItem.ItemType == ItemType.Folder))
								{
									yield return extItem.LocalItem;
								}
							}
						}
					}
					else
					{
						foreach (KeyValuePair<string, ExtendedItem> kvp in extItemCache)
						{
							ExtendedItem extItem = kvp.Value;
							if (extItem.DeletionId == 0 && itemType == DifItemType.Any
								|| (itemType == DifItemType.File && extItem.ItemType == ItemType.File)
								|| (itemType == DifItemType.Folder && extItem.ItemType == ItemType.Folder))
							{
								if (Path.GetDirectoryName(kvp.Key) == path && kvp.Value.ItemType == ItemType.File)
								{
									yield return kvp.Value.LocalItem;
								}
							}
						}
					}
				}
			}
			else
			{
				throw new System.IO.DirectoryNotFoundException(string.Format("Folder {0} does not exist.", path));
			}
		}

		//public IEnumerable<string> GetFolderItems(string path, DifItemType itemType)
		//{
		//  TFServerConnection connection = ServerConnections.GetConnectionForPath(path);
		//  if (FolderExists(path))
		//  {
		//    if (itemType == DifItemType.Any || itemType == DifItemType.File)
		//    {
		//      foreach (string filename in Directory.GetFiles(path))
		//      {
		//        yield return filename;
		//      }
		//    }
		//    if (itemType == DifItemType.Any || itemType == DifItemType.Folder)
		//    {
		//      foreach (string foldername in Directory.GetDirectories(path))
		//      {
		//        // only return folders that have been lizardenated
		//        if (Directory.Exists(connection.GetMetaFolder(foldername)))
		//        {
		//          yield return foldername;
		//        }
		//      }
		//    }
		//  }
		//  else
		//  {
		//    throw new System.IO.DirectoryNotFoundException(string.Format("Folder {0} does not exist.", path));
		//  }
		//}



		public System.IO.Stream GetFileItemStream(string path)
		{
			string localcopy = LizardFileAccess.GetLTFLocalCacheFileName(path);
			try
			{
				LizardFileInfo lfi = LizardFileAccess.GetLizardFileInfo(path);
				Item item = GetItem(path);

				if (lfi != null && lfi.LocalVersion == item.ChangesetId)
				{
					if (File.Exists(localcopy))
					{
						return File.OpenRead(localcopy);
					}
				}
				item.DownloadFile(localcopy);
				return File.OpenRead(localcopy);
			}
			catch
			{
				return null;
			}
		}

		public int GetFileChecksum(string path)
		{
			string localcopy = LizardFileAccess.GetLTFLocalCacheFileName(path);
			try
			{
				LizardFileInfo lfi = LizardFileAccess.GetLizardFileInfo(path);
				Item item = GetItem(path);
				if (lfi != null && lfi.LocalVersion == item.ChangesetId)
				{
					return lfi.LocalVersionChecksum;
				}
				int hs1 = 0, cs1 = 0;
				string downloadPath = string.Format("{0}/{1}", tempPath, Path.GetFileName(path));
				item.DownloadFile(downloadPath);
				int fh1 = MapFileAndCheckSumA(path, ref hs1, ref cs1);
				File.Delete(downloadPath);
				return cs1;
			}
			catch
			{
				return -1;
			}
		}

		private Item GetItem(string path)
		{
			if (extItemCache != null && extItemCache.ContainsKey(path))
				if (itemCache != null && itemCache.ContainsKey(extItemCache[path].SourceServerItem))
					return itemCache[extItemCache[path].SourceServerItem];

			string folderPath = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			WorkspaceInfo wsi = Workstation.Current.GetLocalWorkspaceInfo(folderPath);
			if (wsi != null && folderPath != string.Empty)
			{
				string serverItem = folderPath + "/" + fileName;
				Workspace ws = wsi.GetWorkspace(vcServer.TeamFoundationServer);
				ItemSpec ispec = new ItemSpec(serverItem, RecursionType.None);
				ExtendedItem[] eItems = ws.GetExtendedItems(new ItemSpec[] { ispec }, DeletedState.NonDeleted, ItemType.File)[0];
				if (eItems.Length > 0)
				{
					ExtendedItem ei = eItems[0];
					int version = ei.VersionLocal;
					Item i = null;
					if (ei.VersionLocal > 0)
						i = vcServer.GetItem(ei.ItemId, ei.VersionLocal);
					else
						throw new System.IO.FileNotFoundException();

					lastItemHasPotentialConflict = (ei.VersionLocal != ei.VersionLatest);
					return i;
				}
			}
			throw new System.IO.FileNotFoundException();
		}
		bool lastItemHasPotentialConflict = false;
		public bool LastItemHasPotentialConflict
		{
			get { return lastItemHasPotentialConflict; }
		}

		public int GetQuickItemCount(TFSettings settings, string path)
		{
			List<string> list = new List<string>();
			string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
			foreach (string f in files)
				if (settings.IsFullFilePathIncluded(f)) list.Add(f);
			return list.Count;

		}

		public string GetVersionQualifiedPath(string path)
		{
			return LizardFileAccess.SetPathVersion(path, version);
		}


		#endregion
	}
}
